#!/usr/bin/python

import sys
import math
import numpy as np

from PySide.QtCore import *
from PySide.QtGui import *

class ImageItem(QGraphicsItem):
    """ Image Item to show the scaled pixmap"""

    scale = int(5)
    def __init__(self, pixmap, parent=None):
        super(ImageItem, self).__init__(parent)
        self._pixmap = pixmap
        size = self._pixmap.size() * self.scale
        self._target_rect = QRect(QPoint(-size.width()/2, -size.height()/ 2), size)

    def boundingRect(self):
        return self._target_rect

    def paint(self, painter, option, widget):
        source_rect = QRect(QPoint(0,0), self._pixmap.size())
        painter.drawPixmap(self._target_rect, self._pixmap, source_rect)


class ImageScene(QGraphicsScene):
    """ Image Scene to capture the mouse move in image scene """

    pose = Signal(QPoint)
    def __init__(self, parent=None):
        super(ImageScene, self).__init__(parent)

    def mouseMoveEvent(self, event):
        items = self.items()
        if len(items) == 0:
            return

        img_rect = self.sceneRect()
        pos_in_scene = event.scenePos()
        if not img_rect.contains(pos_in_scene):
            return

        x = pos_in_scene.x()-img_rect.x()
        y = pos_in_scene.y()-img_rect.y()
        pose = QPoint(int(x)/ImageItem.scale, int(y)/ImageItem.scale)

        self.pose.emit(pose)
        text = '(x=%d, v=%d)\n%s' % (pose.x(), pose.y(), 'color')

        QToolTip.showText(event.screenPos(), text)


class ImageView(QGraphicsView):
    """ Image View to show the image in detail """

    def __init__(self, pixmap, parent=None):
        super(ImageView, self).__init__(parent)

        self._pixmap = pixmap
        scale = ImageItem.scale * 2
        size = pixmap.size() * scale

        scene = ImageScene(self)
        self.setSceneRect(QRect(-size.width()/2, -size.height()/2, size.width(), size.height()))
        self.setScene(scene)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        # self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)

        image_item = ImageItem(self._pixmap)
        scene.addItem(image_item)
        image_item.setPos(0,0)

        self.fitInView(self.sceneRect(), Qt.KeepAspectRatio)

    def wheelEvent(self, event):
        scaleFactor = math.pow(2.0, -event.delta() / 240.0)
        factor = self.matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width()
        if factor < 0.7 or factor > 200:
            return

        self.scale(scaleFactor, scaleFactor)

    def drawForeground(self, painter, rect):

        sceneRect = self.sceneRect()

        # print(sceneRect.width(), sceneRect.height())
        message = self.tr("Click and drag the nodes around, and zoom with the "
                          "mouse wheel or the '+' and '-' keys")

        font = painter.font()
        font.setBold(True)
        font.setPointSize(1)
        painter.setFont(font)
        painter.setPen(Qt.lightGray)
        # painter.drawText(textRect.translated(2, 2), 'hello')
        painter.setPen(Qt.black)
        # painter.drawText(textRect, 'hello')


class ImageList(QListWidget):
    ''' A specialized QListWidget that displays the list of all image. '''
    _GRID_SIZE_W = 200
    _GRID_SIZE_H = 60

    def __init__(self, parent=None):
        super(ImageList, self).__init__(parent)

        self.setIconSize(QSize(60, 60))
        self.setGridSize(QSize(ImageList._GRID_SIZE_W, ImageList._GRID_SIZE_H))
        self.setFixedWidth(ImageList._GRID_SIZE_W)


class MainWindow(QWidget):
    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)

        self._images = []
        for i in range(10):
            image = np.random.randint(0, 255, size=(100, 10*(1+i), 3)).astype(np.uint8)
            self._images.append(QPixmap.fromImage(QImage(image, image.shape[0], image.shape[1], QImage.Format_RGB888)))

        self.pixel_pose = QPoint()
        """ Image View Page"""
        image_view_layout = QVBoxLayout()
        self._image_view = QStackedWidget()
        self._value_label = QLabel("(x=, v=)")
        self._value_label.setFont(QFont("Roman times", 9, QFont.Normal) )
        self._value_label.setAlignment(Qt.AlignLeft)
        image_view_layout.addWidget(self._image_view)
        image_view_layout.addWidget(self._value_label)

        """ Image List"""
        self._image_list = ImageList()
        self._image_list.currentItemChanged.connect(self.updateImageInView)

        for image in self._images:
            image_item = QListWidgetItem(self._image_list)
            image_item.setIcon(image)
            image_item.setText('cv::Mat\nCV_8UC1\n60x90')
            self._image_list.addItem(image_item)

            self._image_view.addWidget(ImageView(image))

        main_layout = QHBoxLayout()
        main_layout.addWidget(self._image_list)
        main_layout.addLayout(image_view_layout)

        self.setLayout(main_layout)

        self.setWindowTitle("Image Watch")
        self.setMinimumSize(720, 480)
        self.resize(720, 480)

        self.setMouseTracking(True)

    def updateImageInView(self, current, previous):
        index = self._image_list.row(current)
        self._image_view.setCurrentIndex(index)
        current_show = self._image_view.currentWidget()
        current_show.scene().pose.connect(self.updateText) # only one widget is active, so it's acceptable

    def updateText(self, pose):
        show_text = '(x=%d, v=%d)~' % (pose.x(), pose.y())
        self._value_label.setText(show_text)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    frame = MainWindow()
    frame.show()

    app.exec_()